/*
   @Copyright:LibreOJ
   @Author:   tjyemail
   @Problem:  https://loj.ac/problem/123
   @Language: C++
   @Datetime: 20-07-30 11:07
   */
// Kruskal+fread, time O(ElogE + V + UFS), 582ms

#include <bits/stdc++.h>
using namespace std;

int roots[200005]; // vertex's root
struct Edge {
	int a, b, c; // vertex, cost
	bool operator<(const Edge &e) const { return c>e.c; } // mini-heap
};

inline int find(int leaf)
{
	return leaf==roots[leaf] ? leaf : roots[leaf]=find(roots[leaf]);
}

typedef int _FR_TYPE;
char _FR_BUF[102400];
struct _FR {
	char *buf;
	size_t size, block, idx, end;
	_FR_TYPE num;
	_FR(char *_buf, size_t _size, size_t _block):buf(_buf), size(_size), block(_block){idx=end=size;}
	inline _FR_TYPE read() {
		if (idx > size - block && end == size) {
			memmove(buf, buf + idx, end - idx);
			end = size - idx + fread(buf + size - idx, 1, idx, stdin);
			idx = 0;
		}
		for (num=0; !isdigit(buf[idx]); ++idx);
		for (; isdigit(buf[idx]); ++idx)
			num = num * 10LL + buf[idx] - '0';
		return num;
	}
} fr(_FR_BUF, sizeof(_FR_BUF), 16);

int main()
{
	int v, e, a, b, c;
	priority_queue<Edge> edges; // mini-heap
	for(v=fr.read(), e=fr.read(); e--;) { // v vertexs, e edges
		a=fr.read(), b=fr.read(), c=fr.read();
		edges.push({a, b, c}); // a->b , cost
		roots[a]=a;
		roots[b]=b;
	}
	long long cost=0;
	// must have v-1 edges - kruskal
	for(--v; v && !edges.empty(); edges.pop()) {
		const auto &t = edges.top();
		a = find(t.a), b = find(t.b);
		if (a==b) continue; // have same root ==> circle
		--v;
		roots[b]=a; // join
		cost+=t.c;
	}
	// todo : check it is MST
	printf("%lld\n", cost);
	return 0;
}
